<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>


  <script>
    const fn = (name) => {
      console.log('%c [  ]-14', 'font-size:13px; background:pink; color:#bf2c9f;', name);
    }

    const p2 = new Proxy(fn, {
      apply (target, thisArg, argsArray) {
        console.log('%c [ argsArray ]-18', 'font-size:13px; background:pink; color:#bf2c9f;', argsArray);
        console.log('%c [ thisArg ]-18', 'font-size:13px; background:pink; color:#bf2c9f;', thisArg);
        console.log('%c [ target ]-18', 'font-size:13px; background:pink; color:#bf2c9f;', target);
        target.call(thisArg, argsArray)
      }
    })

    p2('Rex')


    const obj = {
      foo: 1,
    }
    const obj2 = {
      foo: 2
    }

    console.log('%c [  ]-35', 'font-size:13px; background:pink; color:#bf2c9f;', Reflect.get(obj, 'foo'));

    console.log('%c [  ]-37', 'font-size:13px; background:pink; color:#bf2c9f;', Reflect.get(obj, 'foo', obj2));

    // --------------------------------------------
    let activeEffect

    const effectStack = []

    function effect (fn, options = {}) {

      const effectFn = () => {
        cleanup(effectFn)
        activeEffect = effectFn
        effectStack.push(effectFn)
        const res = fn()
        effectStack.pop()

        activeEffect = effectStack[effectStack.length - 1]

        return res
      }


      effectFn.options = options
      effectFn.deps = []

      if (!effectFn.options.lazy) {
        effectFn()
      }

      return effectFn
    }

    function cleanup (effectFn) {
      for (let i = 0; i < effectFn.deps.length; i++) {
        const deps = effectFn.deps[i]
        deps.delete(effectFn)
      }

      effectFn.deps.length = 0
    }

    const bucket = new WeakMap()

    const track = (target, key) => {
      if (!activeEffect) {
        return target[key]
      }

      // 1. 获取当前对象对应的依赖集合
      let depsMap = bucket.get(target)

      if (!depsMap) {
        depsMap = new Map()
        bucket.set(target, depsMap)
      }

      // 2. 获取当前属性对应的依赖集合
      let deps = depsMap.get(key)

      if (!deps) {
        deps = new Set()
        depsMap.set(key, deps)
      }

      deps.add(activeEffect)

      activeEffect.deps.push(deps)

    }

    const trigger = (target, key) => {
      // 1. 获取当前对象对应的依赖集合
      const depsMap = bucket.get(target)
      if (!depsMap) return

      // 2. 获取当前属性对应的依赖集合
      const effects = depsMap.get(key)

      // 3. 执行依赖函数
      const effectsToRun = new Set()
      effects && effects.forEach((fn) => {
        if (activeEffect !== fn) { // 避免自己执行自己 无限递归爆栈
          effectsToRun.add(fn)
        }
      })

      effectsToRun && effectsToRun.forEach((effectFn) => {
        // 如果存在调度器 则调用调度器 把函数作为参数传入
        if (effectFn.options.scheduler) {
          effectFn.options.scheduler(effectFn)
        } else {
          effectFn()
        }
      })
    }

    
    const obj3 = {
      foo: 1,
      get bar(){
        return this.foo
      }
    }

    const p = new Proxy(obj3, {
      get (target, key, receiver) {
        track(target, key)
        // return target[key]
        return Reflect.get(target, key, receiver)
      },

      set (target, key, newValue) {
        target[key] = newValue
        trigger(target, key)
      }
    })

    effect(()=>{
      console.log('%c [  ]-158', 'font-size:13px; background:pink; color:#bf2c9f;', p.bar);
    })
    p.foo++


  </script>
</body>

</html>